feat: add ZSTD compression support for Holotree archives#64
Conversation
c13f34f to
781914e
Compare
PR #64 Response to Architectural Feedback@vjmp - I owe you a proper response to the questions you raised on #66. Let me address each one directly, with benchmark data from a controlled test environment (Python 3.12, rpaframework, robocorp-browser, requests - 12,038 files, 237MB compressed). Benchmark Results
Where LIFT time actually goes: The honest reality: 86% of LIFT time is in external package managers. RCC controls about 8 seconds of a 45 second build. Addressing Your Questions from #661. Why is additional speed important? And on which use-case?Target use-case: First-time LIFT on a developer machine. Not targeting:
Who benefits:
The 4 second improvement on LIFT is a 47% speedup on the RCC-controlled portion, but only 8% on overall user experience because micromamba and uv dominate. 2. Which is more important, speed or simplicity of algorithm?Simplicity. You are right to push back here. The zstd format change itself is simple:
What I added that is NOT simple: the prefetching system (LRU cache, adaptive depth, hit rate tracking, backpressure). I am reconsidering whether to keep it. 3. Does this new format support parallel/concurrent access?Yes, unchanged from current design:
The zstd change does not alter the concurrency model at all. 4. Can you keep this algorithm in your head?The zstd format detection and dual-read: yes. The prefetching system (4 workers, LRU, adaptive depth, backpressure): no, honestly. This is a strong signal that I should remove the prefetching code. 5. When new environments add just few files, how accessing them will be done?Unchanged. This PR does not introduce packfiles. Filesystem is still the index. File existence check is still: does 6. Does this reduce or increase disk space usage?Neutral. Benchmark shows 237MB with both gzip and zstd for the same environment. Zstd at default compression level produces similar sizes to gzip for this workload (mostly Python bytecode, text files, small binaries). 7. Does this remove new plan for GC?No. GC is completely unaffected. Files are still individual, still addressed by hash, still cleaned up the same way. 8. If something corrupts one byte in middle of pack, does it invalidate all environments?Not applicable to this PR. This PR does not introduce packfiles. Each file in hololib remains independent. If one file is corrupted, only environments that need exactly that file are affected. The corruption blast radius is unchanged from current behavior. I explored packfiles in issue #66 as research, but concluded the complexity does not justify the gains - especially given your concerns about long-term maintainability. I am not pursuing packfiles. 9. If there is custom pack file format, how to tell enterprises how to check content?Not applicable. No packfiles in this PR. Files are still "just zstd-compressed files" (or gzip for older catalogs). Standard tools can inspect them:
Enterprises can still audit the hololib the same way they do today. 10. What happens when pack files are accessed concurrently?Not applicable. No packfiles. Concurrent access model is unchanged: multiple processes can read from hololib simultaneously, writes are coordinated via atomic 11. Is it ok that same hash/identity is on multiple pack files?Not applicable. No packfiles in this PR. The identity model is unchanged: one hash = one file in On Your Design Philosophy NotesYou wrote:
I understand and respect this. The long game matters more than benchmarks.
This PR preserves this completely. No separate index files, no packfile lookup tables. The filesystem path IS the lookup key.
Still true. No change to corruption isolation.
Still true. Deduplication works the same way. What This PR Keeps
What I Should RemoveThe prefetching system. Based on your feedback and my own inability to "keep it in my head," the complexity is not justified. Profiling shows syscalls are 39% of CPU time - prefetching reorders reads but does not reduce syscall count. Proposed Path ForwardShip this PR with:
Remove:
Close issue #66 as "research complete, not pursuing packfiles." What do you think? I want to make sure any changes are net-positive for long-term maintainability, and I hear your concerns about complexity. |
…bility This PR adds zstd compression to holotree operations while maintaining full backward compatibility with existing gzip-compressed files. Key changes: - Magic byte detection for automatic format detection (zstd vs gzip) - Dual codec support with sync.Pool for encoder/decoder reuse - Platform-specific compression: zstd on Linux/macOS, gzip on Windows - Race condition fixes for symlinks and .part file handling - Conservative worker count on Windows to avoid filesystem contention Benchmark results (12,038 files, 237MB environment): - LIFT (first build): 48.9s -> 44.95s (-8%, -4s) - DROP (restore): 0.76s -> 0.66s (-13%) - Hololib size: unchanged (237MB) The filesystem-as-index design is preserved. Each file in hololib remains independent with no packfile format. Corruption isolation, parallel access, and GC behavior are unchanged. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
21ea76e to
2a3e1a3
Compare
Summary
This PR implements ZSTD compression for Holotree archives, replacing gzip with a faster and more efficient compression algorithm. The implementation is fully backward compatible with existing gzip archives.
Version: v19.0.0
Benchmark Results
Key Features
ZSTD Compression
HTAV1) for future extensibilityPerformance Optimizations
sync.Poolfor compression/decompressionBug Fixes
TryRemovenow gracefully handles "file not found" errors during space conversionTechnical Details
Archive Format
HTAV1magic + 3-byte version)Dependencies
github.com/klauspost/compress v1.17.0- Pure Go ZSTD implementationNew Environment Variables
RCC_WORKER_COUNTRCC_DISABLE_BATCHINGTest Coverage
New Test Suites
backward_compat.robot- Verifies ZSTD support, round-trip testing, dual-format detectioncompression.robot- Verifies hololib compression, holotree check, export/import preservationAll Tests Passing
Files Changed (69 files)
Core Implementation
htfs/delegates.gohtfs/archive.gohtfs/batching.gohtfs/hardlink.gohtfs/cache.gohtfs/prefetch.gohtfs/library.gohtfs/functions.gopathlib/functions.goConfiguration
common/version.gocommon/variables.goanywork/worker.goTests
robot_tests/backward_compat.robotrobot_tests/compression.robotrobot_tests/holotree.robotdocs/changelog.mdUsage
Closes #63
🤖 Generated with Claude Code